import openai
import subprocess
import json
import os
import sys
import difflib
import re
import httpx
import random

def fix_semantic_error(rust_file_path, c_input, c_output, rs_output, description,
        CFG, DDG, c_output_lines, rust_output_lines, output_diff):
    with open(rust_file_path, "r") as rs_file:
        rs_code = rs_file.read()
    result = subprocess.run([f"./ruststub/target/debug/ruststub", rust_file_path], capture_output=True, text=True, timeout=10)
    if result.returncode != 0:
        print("Compilation failed:")
        print(result.stderr)
        return rs_code
    stub_code = result.stdout
    print(f"stub:{stub_code}")
    has_error, errors = check_rust_code(stub_code)
    stub_file_name = "tmp_gen_stub.rs"
    if not has_error:
        with open(stub_file_name, "w", encoding="utf-8") as c_rust:
            print(stub_code, file=c_rust)
    else:
        print(f"Error to check rust code snippet:{error}")
        corrected_rust_code = fix_errors_with_gpt4(error, stub_code)
        print(f"Corrected rust code:\n")
        print(corrected_rust_code)
        with open(stub_file_name, "w", encoding="utf-8") as c_rust:
            print(corrected_rust_code, file=c_rust)
    with open(stub_file_name, "r") as sf:
        stub_code = sf.read()
    has_error, errors = check_rust_code(stub_code)
    if has_error:
        print("Compilation failed:")
        print(errors)
        return rs_code

    from rust_error import run_rust_file
    has_error, cargo_output = run_rust_file(stub_file_name, c_input)
    
    if has_error:
        print("Compilation failed:")
        print(cargo_output)
        return rs_code
    stub_output = cargo_output
    stub_output = stub_output.split('\n')
    if len(stub_output) > 100:
        stub_output="\n".join(stub_output[:100])
    else:
        stub_output = "\n".join(stub_output)
    print(stub_output)
    rust_code = construct_semantic_prompt(rust_file_path, c_input, c_output, rs_output, stub_output, description, CFG, DDG, c_output_lines, rust_output_lines, output_diff)
    return rust_code

def calculate_diff(c_output, rust_output):
    diff = difflib.unified_diff(c_output.splitlines(), rust_output.splitlines(), lineterm='')
    return list(diff)

def compare_outputs(output1, output2, threshold=0.95):
    """Compare the consistency of output between two programs"""
    matcher = difflib.SequenceMatcher(None, output1, output2)
    similarity = matcher.ratio()
    print(f"Similarity: {similarity:.4f}")  # Print similarity value for easy observation
    return similarity >= threshold

def compile_and_run_rust_code(rust_file_path, c_input, c_output, c_description, CFG, DDG, c_output_lines):
    # Compile generated Rust code
    with open(rust_file_path, "r") as rs_file:
        rs_code = rs_file.read()
    has_error, errors = check_rust_code(rs_code)
    if has_error:
        print("Compilation failed:")
        print(errors)
        return rs_code, False
    
    syntax_pass_file.write(f"{random_test_json}\n")
    syntax_pass_file.flush()
    gpt_gen_file = test_file.replace("_output.json", "_gptsyntax.txt")
    gpt_gen_path = os.path.join(gpt_path, gpt_gen_file)
    with open(gpt_gen_path, "w") as gf:
        gf.write(code_snippet) 

    from rust_error import run_rust_file
    # Run the Rust executable file
    has_error, cargo_output = run_rust_file(rust_file_path, c_input)
    if has_error:
        print(f"Fail to run {rust_file_path}!")
        print(cargo_output)
        return rs_code, False
    else:
        print("Program output:")
        print(cargo_output)
        rust_output_lines = get_rust_output_code_lines(rust_file_path)
        print("Rust output code lines:")
        print(rust_output_lines)
        rs_output = cargo_output
        rs_output_strip = re.sub(r'\s+', '', rs_output)
        c_output_strip = re.sub(r'\s+', '', c_output)
        print(f"Rust output:{rs_output_strip}")
        print(f"C output:{c_output_strip}")
        output_diff = calculate_diff(c_output, rs_output)
        output_diff = "\n".join(output_diff)
        if not compare_outputs(rs_output_strip, c_output_strip):
            print("The semantic of generated Rust code is not equal to C code!")
            rs_code = fix_semantic_error(rust_file_path, c_input, c_output, rs_output, c_description, CFG, DDG, c_output_lines, rust_output_lines, output_diff)
        else:
            return rs_code, True

    return rs_code, False
